#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h> 
#include <time.h>

#include "bodyShape.h"

float d = 10; // Indicates the distance of our point of view ( eye ) from the begining of the axis ( 0,0,0 )
float deg = 0;	// Indicates the degree of our point of view ( eye ) from the X axis Anti-Clockwise

/* the reshape callback function */
void reshape(int width, int height){
	float AR,Left,Right,Top,Bottom;
	
	Left	= -5;
	Right	=  5;
    Top		=  5;
    Bottom	= -5;
	
	glViewport(0,0,width,height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	AR =(float)width/height;
	
	if (AR>=1)
	{
		Left=Left*AR;
		Right=Right*AR;
	}else{
		Top=Top/AR;
		Bottom=Bottom/AR;
	}

	gluPerspective(50,AR,1.5,30);
}

/* The callback function of our rendering */
void renderCallBack() 
{
	float x,y;
	glClearColor(0.5f,0.5f,0.5f,1.0f); // set bakground color
	glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); //erase bakground with selected color

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	x = d*cos(deg); // calculating the x-coordinate of our eye in the 3D , distanced from the beginning of the axis (0,0,0)
	y = d*sin(deg); // calculating the y-coordinate of our eye in the 3D , distanced from the beginning of the axis (0,0,0)


	glEnable(GL_DEPTH_TEST);
		gluLookAt(x,y,0,0,0,0,0,0,1); // looking at our rendering from X& Y axis , with up vector ( unified ) pointing to Z axis 
		drawBody(&arg);
	glDisable(GL_DEPTH_TEST);
	glFlush();
}

// the special keyboard function for the spider's arms movement
void keyPress(int key, int x, int y)
{
	switch(key)
	{
	case GLUT_KEY_RIGHT: // rotates the point of view (eye) to the right 
		deg+=0.1;  
		break;
	case GLUT_KEY_LEFT: // rotates the point of view (eye) to the left 
		deg-=0.1;
		break;
	case GLUT_KEY_UP: // advances the camera forward
		d-=0.1;
		break;
	case GLUT_KEY_DOWN: // backwards the camera a bit
		d+=0.1;
		break;
	case GLUT_KEY_END: // rotates the body around x axis
		arg.bodyX+=10;
		break;		
	case GLUT_KEY_HOME: // toggles the increment/decrement flag. ( 1=Anti-Clockwise , -1=ClockWise )
		arg.direction=arg.direction*-1;
		break;
	case GLUT_KEY_PAGE_DOWN: // sets the the increment/decrementflag to 1 ( for anti-clockwise rotation).
		arg.direction=1;
		break;
	case GLUT_KEY_PAGE_UP: // sets the the increment/decrementflag to -1 ( for clockwise rotation ).
		arg.direction=-1;
		break;
	case GLUT_KEY_INSERT:  // adds/subs the angle of the upper right arm second extension ( around Y axis ).
		arg.UpperRightE2Degree= (arg.UpperRightE2Degree+arg.direction*10) % 360 ;
		break;

	case GLUT_KEY_F1: // adds/subs the angle of the upper right arm (around Z axis)
		arg.UpperRightDegree=(arg.UpperRightDegree+arg.direction*10 ) % 360 ;
		break;
    case GLUT_KEY_F2: // adds/subs the angle of the upper right arm (around Y axis)
		arg.UpperRightYDegree=(arg.UpperRightYDegree+arg.direction*10 ) % 360 ;
		break;
    case GLUT_KEY_F3: // adds/subs the angle of the upper right arm extension (around Y&Z axis)
		arg.UpperRightExtensionDegree=(arg.UpperRightExtensionDegree+arg.direction*10 ) % 360 ;
			break;

	case GLUT_KEY_F4:  // adds/subs the angle of the upper left arm (around Z axis)
		arg.UpperLeftDegree=(arg.UpperLeftDegree+arg.direction*10 ) % 360 ;
			break;
	case GLUT_KEY_F5:  // adds/subs the angle of the upper left arm (around Y axis)
		arg.UpperLeftYDegree=(arg.UpperLeftYDegree+arg.direction*10 ) % 360 ;
			break;
	case GLUT_KEY_F6: // adds/subs the angle of the upper left arm extension (around Y&Z axis)
		arg.UpperLeftExtensionDegree=(arg.UpperLeftExtensionDegree+arg.direction*10 ) % 360 ;
			break;

	case GLUT_KEY_F7: // adds/subs the angle of the lower right arm (around Z axis)
		arg.LowerRightDegree=(arg.LowerRightDegree+arg.direction*10 ) % 360 ;
			break;
	case GLUT_KEY_F8: // adds/subs the angle of the lower right arm (around Y axis)
		arg.LowerRightYDegree=(arg.LowerRightYDegree+arg.direction*10 ) % 360 ;
			break;
	case GLUT_KEY_F9: // adds/subs the angle of the lower right arm extension (around Y&Z axis)
		arg.LowerRightExtensionDegree=(arg.LowerRightExtensionDegree+arg.direction*10 ) % 360 ;
			break;
	
	case GLUT_KEY_F10: // adds/subs the angle of the lower left arm (around Z axis)
		arg.LowerLeftDegree=(arg.LowerLeftDegree+arg.direction*10 ) % 360 ;
			break;
	case GLUT_KEY_F11: // adds/subs the angle of the lower left arm (around Y axis)
		arg.LowerLeftYDegree=(arg.LowerLeftYDegree+arg.direction*10 ) % 360 ;
			break;
	case GLUT_KEY_F12: // adds/subs the angle of the lowe left arm extension (around Y&Z axis)
		arg.LowerLeftExtensionDegree=(arg.LowerLeftExtensionDegree+arg.direction*10 ) % 360 ;
			break;
	}
	

	glutPostRedisplay(); // re-calling the renderCallBack() function after the renedering parameters where changed
}


// the keyboard function for saving the spider status and quitting the application
void ourKBfunc(unsigned char key, int x, int y)
{
	switch(key)
	{
	case 'q':
		BodyFileSave(); // Saving the current parameters of the spider's arms and juncturas to the file : body.txt
		glutDestroyWindow(id);	// Close the Window of our application ( identified by the variable : id )
		break;
	case 's':
		BodyFileSave(); // Saving the current parameters of the spider's arms and juncturas to the file : body.txt
		break;
			
	default:
		break;
	}
}



// the spider's body animation when the application is in an idle state
void idle()
{
	switch(rand()%50)
	{
	case 0:
		arg.UpperRightDegree+=1;
		break;
	case 1:
		arg.UpperRightExtensionDegree+=1;
			break;
	case 2:
		arg.UpperLeftDegree+=1;
			break;
	case 3:
		arg.UpperLeftExtensionDegree+=1;
			break;
	case 4:
		arg.LowerRightDegree+=1;
			break;
	case 5:
		arg.LowerRightExtensionDegree+=1;
			break;
	case 6:
		arg.LowerLeftDegree+=1;
			break;
	case 7:
		arg.LowerLeftExtensionDegree+=1;
	case 8:
		arg.UpperRightDegree-=1;
		break;
	case 9:
		arg.UpperRightExtensionDegree-=1;
			break;
	case 10:
		arg.UpperLeftDegree-=1;
			break;
	case 11:
		arg.UpperLeftExtensionDegree-=1;
			break;
	case 12:
		arg.LowerRightDegree-=1;
			break;
	case 13:
		arg.LowerRightExtensionDegree-=1;
			break;
	case 14:
		arg.LowerLeftDegree-=1;
			break;
	case 15:
		arg.LowerLeftExtensionDegree-=1;
		break;
	case 16:
		arg.UpperRightE2Degree-=arg.direction;
		break;
	case 17:
		arg.LowerLeftYDegree-=arg.direction;
		break;
	case 18:
		arg.UpperLeftYDegree-=arg.direction;
		break;
	case 19:
		arg.LowerRightYDegree-=arg.direction;
		break;
	case 20:
		arg.UpperRightYDegree-=arg.direction;
		break;
	default:
		break;
	}
	glutPostRedisplay();
}
arg.LowerRightExtensionDegree-=1;
			break;
	case 14:
		arg.LowerLeftDegree-=1;
			break;
	case 15:
		arg.LowerLeftExtensionDegree-=1;
		break;
	case 16:
		arg.UpperRightE2Degree-=arg.direction;
		break;
	case 17:
		arg.LowerLeftYDegree-=arg.direction;
		break;
	case 18:
		arg.UpperLeftYDegree-=arg.direction;
		break;
	case 19:
		arg.LowerRightYDegree-